package fr.vvins.core.services;

import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.ws.rs.Path;

import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;

import fr.vvins.core.biz.exception.BizException;
import fr.vvins.core.biz.user.UserException;
import fr.vvins.core.biz.user.UserManager;
import fr.vvins.core.biz.user.dto.CredentialDto;
import fr.vvins.core.biz.user.dto.FavoriteDto;
import fr.vvins.core.biz.user.dto.UserCommentDto;
import fr.vvins.core.biz.user.dto.UserContactDto;
import fr.vvins.core.biz.user.dto.UserDto;
import fr.vvins.core.biz.user.dto.UserDtoInfo;
import fr.vvins.core.biz.user.dto.UserLogDto;
import fr.vvins.core.common.TechnicalException;

@Path("/user")
@Component("userService")
public class UserServiceImpl implements UserService {
	@Resource(name = "userManager")
	private UserManager manager;

	@Override
	public String authenticate(String token) throws BizException, TechnicalException {
		if(StringUtils.isEmpty(token)){
			throw new UserException(UserException.TOKEN_EMPTY, "Token should not be empty");
		}
		Integer userId = manager.decrypt(token);
		return manager.crypt(userId);
	}

	@Override
	public String createUser(UserDto dto) throws BizException, TechnicalException {
		if(dto == null){
			throw new UserException(UserException.USER_DTO_EMPTY, "UserDto should not be empty");
		}
		 dto = manager.createUser(dto);
		 return manager.crypt(dto.getId()); 
	}

	@Override
	public String generateToken(CredentialDto credential) throws BizException, TechnicalException {
		if(credential == null){
			throw new UserException(UserException.CREDENTIAL_EMPTY, "Credential should not be empty");
		}
		UserDto dto = manager.authenticate(credential);
		return manager.crypt(dto.getId());
	}

	@Override
	public void addLog(String token, String entity, String entityId, String actionId) throws BizException, TechnicalException {
		if(StringUtils.isEmpty(token)){
			throw new UserException(UserException.TOKEN_EMPTY, "Token should not be empty");
		}
		if(StringUtils.isEmpty(entityId) || StringUtils.isEmpty(entity)){
			throw new UserException(UserException.ENTITY_EMPTY, "Entity and entityID should not be empty");
		}
		Integer userId = manager.decrypt(token);;
		try{
			Integer.parseInt(entityId);
		} catch (NumberFormatException e) {
			throw new UserException(UserException.ENTITY_EMPTY, "Entity id should not be an integer");
		}
		manager.addLog(userId, entity, Integer.parseInt(entityId), Integer.parseInt(actionId));
	}

	@Override
	public List<UserLogDto> getLastLog(String token) throws BizException, TechnicalException {
		if(StringUtils.isEmpty(token)){
			throw new UserException(UserException.TOKEN_EMPTY, "Token should not be empty");
		}
		Integer userId = manager.decrypt(token);
		return manager.getLastLog(userId);
	}

	@Override
	public void addFavorite(String token, String entity, String id) throws BizException, TechnicalException {
		if(StringUtils.isEmpty(token)){
			throw new UserException(UserException.TOKEN_EMPTY, "Token should not be empty");
		}
		if(StringUtils.isEmpty(entity)){
			throw new UserException(UserException.ENTITY_EMPTY, "Entity should not be empty");
		}
		if(StringUtils.isEmpty(id)){
			throw new UserException(UserException.ENTITY_ID_EMPTY, "Entity id should not be empty");
		}
		try{
			Integer.parseInt(id);
		} catch (NumberFormatException e) {
			throw new UserException(UserException.ENTITY_ID_EMPTY, "Entity id should not be an integer");
		}
		Integer userId = manager.decrypt(token);
		manager.addFavorite(userId, entity, Integer.parseInt(id));
	}

	@Override
	public List<FavoriteDto> getFavorites(String token) throws BizException, TechnicalException {
		if(StringUtils.isEmpty(token)){
			throw new UserException(UserException.TOKEN_EMPTY, "Token should not be empty");
		}
		Integer userId = manager.decrypt(token);
		return manager.getFavorites(userId);
	}

	@Override
	public List<FavoriteDto> getUserFavorites(String token, String userId) throws BizException, TechnicalException {
		if(StringUtils.isEmpty(token)){
			throw new UserException(UserException.TOKEN_EMPTY, "Token should not be empty");
		}
		if(StringUtils.isEmpty(userId)){
			throw new UserException(UserException.USER_ID_EMPTY, "User id should not be empty");
		}
		try{
			Integer.parseInt(userId);
		} catch (NumberFormatException e) {
			throw new UserException(UserException.USER_ID_EMPTY, "User id should not be an integer");
		}
		Integer askUserId = manager.decrypt(token);
		return manager.getUserFavorites(askUserId, Integer.parseInt(userId));
	}

	@Override
	public void removeFavorite(String token, String entity, String id) throws BizException, TechnicalException {
		if(StringUtils.isEmpty(token)){
			throw new UserException(UserException.TOKEN_EMPTY, "Token should not be empty");
		}
		if(StringUtils.isEmpty(entity)){
			throw new UserException(UserException.ENTITY_EMPTY, "Entity should not be empty");
		}
		if(StringUtils.isEmpty(id)){
			throw new UserException(UserException.ENTITY_ID_EMPTY, "Entity id should not be empty");
		}
		try{
			Integer.parseInt(id);
		} catch (NumberFormatException e) {
			throw new UserException(UserException.ENTITY_ID_EMPTY, "Entity id should not be an integer");
		}
		Integer userId = manager.decrypt(token);
		manager.removeFavorite(userId, entity, Integer.parseInt(id));
	}

	@Override
	public void addFollowing(String token, String userId) throws BizException, TechnicalException {
		if(StringUtils.isEmpty(token)){
			throw new UserException(UserException.TOKEN_EMPTY, "Token should not be empty");
		}
		if(StringUtils.isEmpty(userId)){
			throw new UserException(UserException.USER_ID_EMPTY, "User id should not be empty");
		}
		try{
			Integer.parseInt(userId);
		} catch (NumberFormatException e) {
			throw new UserException(UserException.USER_ID_EMPTY, "User id should not be an integer");
		}
		Integer tokenUserId = manager.decrypt(token);
		manager.addFollowing(tokenUserId, Integer.parseInt(userId));
	}

	@Override
	public List<UserDtoInfo> getFollowing(String token) throws BizException, TechnicalException {
		if(StringUtils.isEmpty(token)){
			throw new UserException(UserException.TOKEN_EMPTY, "Token should not be empty");
		}
		Integer tokenUserId = manager.decrypt(token);
		return manager.getFollowing(tokenUserId);
	}
	

	@Override
	public List<UserDtoInfo> getUserFollowing(String token, String userId) throws BizException, TechnicalException {
		if(StringUtils.isEmpty(token)){
			throw new UserException(UserException.TOKEN_EMPTY, "Token should not be empty");
		}
		if(StringUtils.isEmpty(userId)){
			throw new UserException(UserException.USER_ID_EMPTY, "User id should not be empty");
		}
		try{
			Integer.parseInt(userId);
		} catch (NumberFormatException e) {
			throw new UserException(UserException.USER_ID_EMPTY, "User id should not be an integer");
		}
		Integer tokenUserId = manager.decrypt(token);
		return manager.getUserFollowing(tokenUserId, Integer.parseInt(userId));
	}
	
	@Override
	public List<UserDtoInfo> getUserFollowers(String token, String userId) throws BizException, TechnicalException {
		if(StringUtils.isEmpty(token)){
			throw new UserException(UserException.TOKEN_EMPTY, "Token should not be empty");
		}
		if(StringUtils.isEmpty(userId)){
			throw new UserException(UserException.USER_ID_EMPTY, "User id should not be empty");
		}
		try{
			Integer.parseInt(userId);
		} catch (NumberFormatException e) {
			throw new UserException(UserException.USER_ID_EMPTY, "User id should not be an integer");
		}
		Integer tokenUserId = manager.decrypt(token);
		return manager.getUserFollowers(tokenUserId, Integer.parseInt(userId));
	}


	@Override
	public void removeFollowing(String token, String userId) throws BizException, TechnicalException {
		if(StringUtils.isEmpty(token)){
			throw new UserException(UserException.TOKEN_EMPTY, "Token should not be empty");
		}
		if(StringUtils.isEmpty(userId)){
			throw new UserException(UserException.USER_ID_EMPTY, "User id should not be empty");
		}
		try{
			Integer.parseInt(userId);
		} catch (NumberFormatException e) {
			throw new UserException(UserException.USER_ID_EMPTY, "User id should not be an integer");
		}
		Integer tokenUserId = manager.decrypt(token);
		manager.removeFollowing(tokenUserId, Integer.parseInt(userId));
	}

	@Override
	public void addContactInfo(String token, UserContactDto contact) throws BizException, TechnicalException {
		if(StringUtils.isEmpty(token)){
			throw new UserException(UserException.TOKEN_EMPTY, "Token should not be empty");
		}
		if(contact == null){
			throw new UserException(UserException.CONTACT_EMPTY, "Contact info should not be null");
		}
		Integer tokenUserId = manager.decrypt(token);
		manager.addContactInfo(tokenUserId, contact);
	}

	@Override
	public List<UserContactDto> getContactInfo(String token) throws BizException, TechnicalException {
		if(StringUtils.isEmpty(token)){
			throw new UserException(UserException.TOKEN_EMPTY, "Token should not be empty");
		}
		Integer tokenUserId = manager.decrypt(token);
		return manager.getContactInfo(tokenUserId);
	}

	@Override
	public void updateContactInfo(String token, String contactId, Map<String,String> properties) throws BizException, TechnicalException {
		if(StringUtils.isEmpty(token)){
			throw new UserException(UserException.TOKEN_EMPTY, "Token should not be empty");
		}
		if(properties == null){
			throw new UserException(UserException.CONTACT_EMPTY, "Contact properties should not be empty");
		}
		Integer tokenUserId = manager.decrypt(token);
		manager.updateContactInfo(tokenUserId, properties);
	}

	@Override
	public List<UserDtoInfo> getFollowers(String token) throws BizException, TechnicalException {
		if(StringUtils.isEmpty(token)){
			throw new UserException(UserException.TOKEN_EMPTY, "Token should not be empty");
		}
		Integer tokenUserId = manager.decrypt(token);
		return manager.getFollowers(tokenUserId);
	}

	@Override
	public UserDto getUser(String token) throws BizException, TechnicalException {
		if(StringUtils.isEmpty(token)){
			throw new UserException(UserException.TOKEN_EMPTY, "Token should not be empty");
		}
		Integer tokenUserId = manager.decrypt(token);
		return manager.findUserById(tokenUserId);
	}
	
	@Override
	public UserDtoInfo getUserInfo(String token) throws BizException, TechnicalException {
		if(StringUtils.isEmpty(token)){
			throw new UserException(UserException.TOKEN_EMPTY, "Token should not be empty");
		}
		Integer tokenUserId = manager.decrypt(token);
		return manager.findUserInfoById(tokenUserId);
	}

	@Override
	public UserDto updateUser(String token, Map<String,String> properties) throws BizException, TechnicalException {
		if(StringUtils.isEmpty(token)){
			throw new UserException(UserException.TOKEN_EMPTY, "Token should not be empty");
		}
		if(properties == null){
			throw new UserException(UserException.USER_DTO_EMPTY, "User properties should not be empty");
		}
		Integer tokenUserId = manager.decrypt(token);
		return manager.updateUser(tokenUserId, properties);
	}

	@Override
	public List<UserCommentDto> getComments(String token) throws BizException, TechnicalException {
		if(StringUtils.isEmpty(token)){
			throw new UserException(UserException.TOKEN_EMPTY, "Token should not be empty");
		}
		Integer tokenUserId = manager.decrypt(token);
		return manager.getComments(tokenUserId);
	}

	@Override
	public List<UserCommentDto> getUserComments(String token, String userId) throws BizException, TechnicalException {
		if(StringUtils.isEmpty(token)){
			throw new UserException(UserException.TOKEN_EMPTY, "Token should not be empty");
		}
		if(StringUtils.isEmpty(userId)){
			throw new UserException(UserException.USER_ID_EMPTY, "User id should not be empty");
		}
		try{
			Integer.parseInt(userId);
		} catch (NumberFormatException e) {
			throw new UserException(UserException.USER_ID_EMPTY, "User id should not be an integer");
		}
		Integer tokenUserId = manager.decrypt(token);
		return manager.getUserComments(tokenUserId, Integer.parseInt(userId));
	}

	public UserManager getManager() {
		return manager;
	}

	public void setManager(UserManager manager) {
		this.manager = manager;
	}

}
